package demo;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

import javax.naming.event.ObjectChangeListener;
import java.util.Arrays;

/**
 * 定义一个切面类，用于在项目业务逻辑中动态添加逻辑
 */
@Component//该类也需要让Spring容器管理
@Aspect//使用该注解让Spring容器知道它是一个切面类
public class SysoutAspect {
//    /*
//        @Before是切面类中的一个切入点注解，用于表达该方法逻辑是在执行实际方法之前切入并运行
//        方法中需要传入切入点的描述信息(实际切入方法的签名):
//        访问修饰符 返回值类型 方法所属的类.方法名(参数列表)
//        public int CalculatorImpl.sub(..)      这里参数列表中的".."表示任意参数
//                      ^
//           引用类型实际要写完全限定名(包名.类名)
//
//        在方法签名中可以使用"*"模糊匹配，例如:
//        public int com.tedu.aopdemo.aop.CalculatorImpl.*(..)
//                                                       ^
//                                          表示CalculatorImpl中任意方法都要切入
//     */
//    @Before("execution(public int org.tedu.aopdemo.aop.CalculatorImpl.*(..))")
//    public void before(JoinPoint joinPoint) {
//        /*
//            JoinPoint 切入点
//            该类用于描述当前切面切入的方法信息，通过它我们可以得知当前切面切入的方法所属的类，
//            方法名，参数等信息
//         */
//        //切入点方法所属的对象(我们切入的是CalculatorImpl的add方法，因此target是:CalculatorImpl)
////        System.out.println("target"+joinPoint.getTarget());
//        //获取切入方法信息，（Signature签名，这里表示方法签名），通过Signature获取该方法名字(.getName())
////        System.out.println(joinPoint.getSignature().getName());
//        //获取切入方法的参数(实参)
////        System.out.println("参数:"+ Arrays.toString(joinPoint.getArgs()));
//        //获取切入点的方法名
//        String methodName = joinPoint.getSignature().getName();
//        //获取切入点该方法所属类的名字
//        String className = joinPoint.getTarget().getClass().getSimpleName();
//        //获取切入点调用方法实际传入的参数
//        String args = Arrays.toString(joinPoint.getArgs());
//        System.out.println("开始调用"+className+"."+methodName+"(),实参为:"+args);
//    }
//
//    /*
//        @AfterReturning表示切入点为实际方法调用完毕并返回结果后调用
//        该切入点方法除了可以获取切入点信息(joinPoint)，
//        还可以获取实际方法调用后返回的结果(returnValue)
//     */
//    @AfterReturning(
//            value="execution(public int org.tedu.aopdemo.aop.CalculatorImpl.*(..))",
//            returning="returnValue"//说明将实际方法返回值传递给下面方法的哪个参数
//    )
//    public void afterReturning(JoinPoint joinPoint, Object returnValue) {
//        String methodName = joinPoint.getSignature().getName();
//        String className = joinPoint.getTarget().getClass().getSimpleName();
//        System.out.println(className+"."+methodName+"()执行完毕，返回值为:"+returnValue);
//    }
//
//    /*
//        @After切入点是在一个方法执行完毕后。
//        无论该方法是否抛出异常，最后都会走该切面
//        注意该切面不能获取方法返回值
//     */
//    @After("execution(public int org.tedu.aopdemo.aop.CalculatorImpl.*(..))")
//    public void after(JoinPoint joinPoint){
//        String methodName = joinPoint.getSignature().getName();
//        String className = joinPoint.getTarget().getClass().getSimpleName();
//        System.out.println(className+"."+methodName+"()完毕!");
//    }
//    /*
//        @AfterThrowing切入点是在实际方法抛出异常后进行
//     */
//    @AfterThrowing(
//            value = "execution(public int org.tedu.aopdemo.aop.CalculatorImpl.*(..))",
//            throwing = "e"//指定将实际方法抛出的异常传递给下面方法的哪个参数
//    )
//    public void AfterThrowing(JoinPoint joinPoint,Exception e){
//        String methodName = joinPoint.getSignature().getName();
//        String className = joinPoint.getTarget().getClass().getSimpleName();
//        System.out.println(className+"."+methodName+"()抛出异常:"+e.getMessage());
//    }

    /*
        @Around 切入点结合了上述几个
        所有切入点通常用异常处理机制来进行即可
     */
    @Around("execution(public int org.tedu.aopdemo.aop.CalculatorImpl.*(..))")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        String methodName = joinPoint.getSignature().getName();
        String className = joinPoint.getTarget().getClass().getName();
        String args = Arrays.toString(joinPoint.getArgs());

        //@Before里切入的逻辑写在这里
        System.out.println(className + "." + methodName+"()开始执行,参数为:"+args);

        try {
            //实际方法执行，并接收该方法的返回值
            Object returnValue = joinPoint.proceed();//CalculatorImpl.add()执行。。(实际的方法去执行)

            //@AfterReturning
            System.out.println(className + "." + methodName+"()执行完毕");
            return returnValue;
        } catch (Throwable e) {
            throw new RuntimeException(e);
        } finally {
        }

    }

}
